Processing math: 100%


[BZOJ1101]-Zap

https://vjudge.net/problem/HYSBZ-1101

题意略。

gcd(x,y)=d, 相当于求 gcd(x/d,y/d)=1 的个数。相当于求 1xa/d, 1yb/dx, y 互质对数。

n=a/d, m=b/d.

ai=1bj=1[gcd(i,j)==d]=ni=1mj=1[gcd(i,j)==1]

现在必须提到一个莫比乌斯函数的性质:
n>1 时,
d|nμ(d)=0n=1 时,d|nμ(d)=1

证明:

n=1 时显然。

n>1 时,设 $n = p_1^{c_1} p_2^{c_2} p_3^{c_3} p_k^{c_k}d$ 有其中一部分。

显然根据莫比乌斯函数的定义,d 的每个质因子指数为 1 才有贡献,否则 μ(d)=0

那么设 d 中有 r 个质因子。

μ(d)=(1)r ,这样的 dCrm 个。

所以

d|nμ(d)=mr=0(1)rCrm

我们根据二项式定理,逆推回去:

mr=0(1)rCrm=mr=0Crm(1)r1mr=(1+1)m=0

证毕。

我们用这个性质把求和的式子变成:

ni=1mj=1d|gcd(i,j)μ(d)

其中 d|gcd(i,j) 可以变为 d|iandd|j ,更换求和指标,

=nd=1μ(d)ndmd

容易知道 n/d 单调不上升,根据整数分块的知识,最多有 2n 种不同的取值。所以按取值分成 O(n) 个段分别处理,一个连续的段内的和可以用预处理出的莫比乌斯函数前缀和求出。

初次涉及,觉得非常妙,自己想是绝不可能想到的,只能看题解,但据说是套路题,多做做,要有信心。

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <bits/stdc++.h>
using namespace std;

const int N = 5e4 + 10;
int T, a, b, d, tot;
int miu[N], sum[N], pri[N];
bool vis[N];

void get_prefix() {
miu[1] = 1;
for (int i = 2; i <= 50000; i++) {
if (!vis[i]) pri[++tot] = i, miu[i] = -1;
for (int j = 1; j <= tot && i * pri[j] <= 50000; j++) {
vis[i * pri[j]] = 1;
if (i % pri[j] == 0) {
miu[i * pri[j]] = 0;
break;
} else miu[i * pri[j]] = -miu[i];
}
}
for (int i = 1; i <= 50000; i++) sum[i] = sum[i - 1] + miu[i];
}

int cal(int n, int m) {
if (n > m) swap(n, m);
int ans = 0, pos;
for (int i = 1; i <= n; i = pos + 1) {
pos = min(n / (n / i), m / (m / i));
ans += (sum[pos] - sum[i - 1]) * (n / i) * (m / i);
}
return ans;
}

int main() {
ios::sync_with_stdio(false);
get_prefix();
cin >> T;
while (T--) {
cin >> a >> b >> d;
printf("%d\n", cal(a / d, b / d));
}
return 0;
}